package com.aliengen.thingple.driverapp.data.models;

import com.aliengen.thingple.driverapp.data.exception.InvalidTagException;
import com.aliengen.thingple.driverapp.data.local.ProductModel;
import com.aliengen.thingple.driverapp.network.api.models.Cylinder;

import java.util.Calendar;
import java.util.HashMap;

/**
 * This class is part of the Thingple mobile application for the CMC168 Handheld reader.
 *
 * Copyright AlienGen Limited 2016. All rights reserved.
 *
 * @author Timothé Mermet-Buffet <tim@aliengen.com>
 */
public class CylinderTag extends Tag {
    protected static HashMap<byte[], CylinderTag> cylinders = new HashMap<byte[], CylinderTag>();

    protected Cylinder cylinder;

    protected boolean anomaly = false;

    public static CylinderTag get(byte[] tag) throws InvalidTagException
    {
        if(cylinders.containsKey(tag))
        {
            return cylinders.get(tag);
        }

        CylinderTag o = new CylinderTag(tag);
        cylinders.put(tag, o);

        return o;
    }

    public CylinderTag(byte[] tag) throws InvalidTagException
    {
        super(tag);

        if(this.tagType != 0x03)
        {
            throw new InvalidTagException("Not cylinder tag!");
        }

        this.cylinder = new Cylinder();
        this.cylinder.gasTypeId = (b(1) & 0xF0) >> 4;

        this.cylinder.productId = ((b(2) & 0xFF) << 8) + (b(3) & 0xFF);
        this.cylinder.facilityCode = b(4) & 0xFF;
        this.cylinder.tagStatus = b(5) & 0xFF;
        this.cylinder.month = b(6) & 0xFF;
        this.cylinder.day = b(7) & 0xFF;
        this.cylinder.maintenanceWeek = ((b(8) & 0xFF) << 8) + (b(9) & 0xFF);
        this.cylinder.bundleId = ((b(10) & 0xFF) << 8) + (b(11) & 0xFF);
        this.cylinder.bundleReference = String.format("%05d", this.cylinder.bundleId);

        Integer number = ((b(12) & 0xFF) << 24) + ((b(13) & 0xFF) << 16) + ((b(14) & 0xFF) << 8) + (b(15) & 0xFF);

        this.cylinder.huashenNumber = String.format("%08d", number);
    }

    public Boolean isSynchronized()
    {
        return this.cylinder.cylinder_id != 0;
    }

    public void setCylinder(Cylinder cylinder)
    {
        this.cylinder = cylinder;
    }

    public Cylinder getCylinder()
    {
        return this.cylinder;
    }

    public String getReference()
    {
        return this.cylinder.huashenNumber;
    }

    public String getBundleReference() { return this.cylinder.bundleReference; }

    public String getProductName()
    {
        ProductModel product = ProductModel.get(this.cylinder.productId);
        if(product != null) {
            return product.product_name;
        }
        return this.getGasType();
    }

    public String getGasType() {
        switch(this.cylinder.gasTypeId)
        {
            case 0x01:
                return "Nitrogen";
            case 0x02:
                return "Hydrogen";
            case 0x03:
                return "Argon";
            case 0x04:
                return "Mixed";
            case 0x05:
                return "Oxygen";
            case 0x06:
                return "Helium";
            case 0x07:
                return "Acetylene";
            case 0x08:
                return "Propane";
            case 0x09:
                return "Carbon dioxyde";
            case 0x10:
                return "Krypton";
            case 0x11:
                return "Xenon";
            case 0x12:
                return "Natural gas";
            case 0x13:
                return "Methane";
            case 0x14:
                return "Silican";
            case 0x15:
                return "Others";
        }
        return "Unknow";
    }

    public String getPressure() { return isSynchronized() ? this.cylinder.pressure : ""; }

    public String getNextMaintenance() {
        Calendar base = Calendar.getInstance();
        // Set reference to the first of january 2016.
        base.set(2016,1,1,0,0,0);

        // Move the date to the next maintenance week.
        base.add(Calendar.WEEK_OF_YEAR, this.cylinder.maintenanceWeek);

        Calendar now = Calendar.getInstance();

        int weeks = 0;
        while(base.after(now))
        {
            now.add(Calendar.WEEK_OF_YEAR, 1);
            weeks++;
        }

        return "" + weeks;
    }

    public Boolean needMaintenance()
    {
        Calendar base = Calendar.getInstance();
        // Set reference to the first of january 2016.
        base.set(2016,1,1,0,0,0);

        // Move the date to the next maintenance week.
        base.add(Calendar.WEEK_OF_YEAR, this.cylinder.maintenanceWeek);
        Calendar now = Calendar.getInstance();
        return now.after(base);

        //return this.cylinder.maintenanceWeek < 5;
    }

    public Boolean hasProblem() {
        if(this.needMaintenance())
        {
            return true;
        }
        if(this.cylinder.tagStatus == 0x01)
        {
            return true;
        }
        return false;
    }

    public boolean isAnomaly()
    {
        return this.cylinder.tagStatus != 0x00 || anomaly;
    }

    public String getStatus()
    {
        if(this.cylinder.tagStatus == 0x00 && !anomaly) {
            if(this.needMaintenance())
            {
                return "M";
            }
            return "OK";
        }
        return "Anomaly";
    }

    public void setAnomaly(Boolean anomaly)
    {
        this.anomaly = anomaly;
    }

    public String getLastOperation() {
        switch(this.cylinder.operationId)
        {
            case 1:
                return "REGISTRATION";
            case 2:
                return "MAINTENANCE IN";
            case 3:
                return "MAINTENANCE OUT";
            case 4:
                return "CHECK-IN GATE";
            case 5:
                return "CHECK-OUT GATE";
            case 6:
                return "CHECK-IN PLATFORM";
            case 7:
                return "CHECK-OUT PLATFORM";
            case 8:
                return "FILLING START";
            case 9:
                return "FILLING END";
            case 10:
                return "ANOMALY";
            case 11:
                return "MAINTENANCE ROOM";
            case 12:
                return "PICKUP";
            case 13:
                return "DELIVERY";
        }
        return "";
    }

    @Override
    public String toString() {
        return "Cylinder " + this.cylinder.huashenNumber;
    }

}
